﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Diagnostics;
using System.Collections;
using System.Reflection;

namespace Windows_System_Snapshot
{
    static class Program
    {
        // Timeout for each command
        private static int timeOut = 15;

        // GUI or Console mode flag
        public static bool IS_RUNNING_WITH_GUI;

        [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
        static extern bool AllocConsole();

        [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
        static extern bool FreeConsole();

        [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
        static extern bool AttachConsole(int dwProcessId);

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern IntPtr GetForegroundWindow();

        [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            // if there are no arguments, show the GUI.
            if (args.Length == 0)
            {
                GUIMain();
            }
            // if the are arguments, don't show the GUI
            else
            {
                IntPtr ptr = GetForegroundWindow();
                int  u;
                GetWindowThreadProcessId(ptr, out u);
                Process process = Process.GetProcessById(u);

                if (process.ProcessName == "cmd" ) //Is the uppermost window a cmd process?
                {
                    AttachConsole(process.Id);
                    //we have a console to attach to ..
                    ConsoleMain(args);
                }
                else
                {
                    //no console AND we're in console mode ... create a new console.
                    AllocConsole();
                    ConsoleMain(args);
                }
                FreeConsole();
            }
        }

        /// <summary>
        /// start the GUI version.
        /// </summary>
        private static void GUIMain()
        {
            IS_RUNNING_WITH_GUI = true;
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }

        /// <summary>
        /// start the Console version.
        /// </summary>
        /// <param name="args"></param>
        private static void ConsoleMain(string[] args)
        {
            IS_RUNNING_WITH_GUI = false;
            string path = Logic.DEFAULT_OUTPUT_PATH;
            string title = "\nMellanox Technologies\n" +
                                "Windows System Snapshot\n" +
                                "Version: " + new AssemblyName(System.Reflection.Assembly.GetExecutingAssembly().FullName).Version.ToString() + "\n";

            string usageMsg = "\nUsage:\n" +
                            "1. without parameters                Run the application with GUI.\n" +
                            "2. --target <filename.html>          Set the path of the output file (without GUI).\n" +
                            "3. --timeout <seconds>               Set the maximum running time for each command (without GUI).\n" +
                            "                                         default = " + timeOut +"\n";


            ArrayList argsList = getArgsArray(args);

            // show help
            if (argsList.Contains("--help") || (!argsList.Contains("--help") && !argsList.Contains("--timeout") && !argsList.Contains("--target")))
            {
                Console.WriteLine(title + usageMsg);
                System.Environment.Exit(0);
            }

            // set the target file
            if (argsList.Contains("--target"))
            {
                // get the desired file path
                if (argsList.Count > argsList.IndexOf("--target") + 1)
                {
                    path = (string)argsList[argsList.IndexOf("--target") + 1];
                    path = path.ToLower();
                    argsList.RemoveRange(argsList.IndexOf("--target"), 2);
                }
                else
                {
                    Console.WriteLine(title + usageMsg);
                    System.Environment.Exit(0);
                }
                // check if the file name is legal.
                if (!path.EndsWith(".html"))
                {
                    Console.WriteLine(title + "\nError: the target file must have html extension.\n");
                    System.Environment.Exit(0);
                }
            }

            // set the timeout
            if (argsList.Contains("--timeout"))
            {
                // get the desired timeout
                if (argsList.Count > argsList.IndexOf("--timeout") + 1)
                {
                    try
                    {
                        timeOut = Int32.Parse((string)argsList[argsList.IndexOf("--timeout") + 1]);
                        argsList.RemoveRange(argsList.IndexOf("--timeout"), 2);
                    }
                    catch
                    {
                        Console.WriteLine(title + "\nError: timeout must be an interget number.\n");
                        System.Environment.Exit(0);
                    }
                }
                else
                {
                    Console.WriteLine(title + usageMsg);
                    System.Environment.Exit(0);
                }
            }

            // check if there is illegal arguments
            if (argsList.Count != 0)
            {
                Console.WriteLine(title + usageMsg);
                System.Environment.Exit(0);
            }

            // start working..
            Logic logical = new Logic();
            Console.WriteLine(title);
            Console.WriteLine("Gathering the information may take a few minutes. Please wait...");
            logical.setTimeOut(timeOut);
            logical.startNoNewThread(path);
        }

        /// <summary>
        /// convert the arguments array to ArrayList.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        private static ArrayList getArgsArray(string[] args)
        {
            ArrayList argslist = new ArrayList();

            for (int i = 0; i < args.Length; i++)
            {
                argslist.Add(args[i]);
            }
            return argslist;
        }
    }
}
